package com.zhenyi.toupiao.index;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.hashids.Hashids;

import com.cenjiawen.common.IndexController;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.weixin.sdk.api.MediaApi;
import com.jfinal.weixin.sdk.api.MediaFile;
import com.jfinal.weixin.sdk.api.SnsAccessToken;
import com.jfinal.weixin.sdk.api.SnsAccessTokenApi;
import com.jfinal.weixin.sdk.api.SnsApi;
import com.jfinal.weixin.sdk.kit.IpKit;
import com.toupiao.common.model.TpActivity;
import com.toupiao.common.model.TpActivityVote;
import com.toupiao.common.model.TpJoin;
import com.toupiao.common.model.TpOrder;
import com.toupiao.common.model.TpUser;
import com.toupiao.common.model.TpUserVote;
import com.utils.AuthUtils;
import com.utils.PathUtils;
import com.utils.image.UploadUtils;
import com.utils.interceptor.TestInterceptor;
import com.zhenyi.toupiao.core.WXPayUtils;
import com.zhenyi.toupiao.interceptor.AuthInterceptor;
import com.zhenyi.toupiao.interceptor.CountInterceptor;
import com.zhenyi.toupiao.interceptor.WXInterceptor;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.URLUtil;

// @Before({ AuthInterceptor.class, WXInterceptor.class, CountInterceptor.class })
@Before({ WXInterceptor.class, CountInterceptor.class })
public class HomeController extends IndexController {

	protected final int PAGE_SIZE = 50;
	protected final String APP_ID = PropKit.get("TP_APP_ID");
	protected final String APP_SECRET = PropKit.get("TP_APP_SECRET");
	protected Hashids hashids = new Hashids("toupiao", 4);

	protected final Hashids orderHash = new Hashids("tporder", 2);
	private WXPayUtils payUtils = new WXPayUtils(PropKit.get("TP_APP_ID"), PropKit.get("TP_PARTNER"),
			PropKit.get("TP_PARTNER_KEY"), "http://pite.zhen-yee.com/toupiao/bill/billPush");

	private Long getJoinId() {
		try {
			String joinCode = getPara("joinCode");
			if (StrKit.isBlank(joinCode)) {
				return null;
			}
			return hashids.decode(joinCode)[0];
		} catch (Exception e) {
			return null;
		}
	}

	protected String getCode() {
		return getPara(0);
	}

	protected TpUser getUser() {
		String uid = AuthUtils.getTokenUid(this);
		// return TpUser.dao.findById(Long.parseLong(uid));
		return TpUser.dao.findById(2);
	}

	protected Long getCodeId() {
		try {
			String code = getCode();
			if (code == null) {
				return null;
			}
			return hashids.decode(code)[0];
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Clear
	@Before(TestInterceptor.class)
	public void debug() {
		String ip = IpKit.getRealIpV2(getRequest());
		System.out.println(ip);
		AuthUtils.login(String.valueOf(TpUser.dao.findById(2)), this);
		redirect("/toupiao/v4eE");
		renderSuccess();
	}

	/**
	 * 跳转去微信连接
	 */
	@Clear
	public void wx() {
		String rd = "http://zhenyi.cenjiawen.com/auth";
		rd = URLUtil.encode(rd);
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}"
				+ "&redirect_uri={}&response_type=code&scope=snsapi_userinfo&state=#wechat_redirect";
		url = StrFormatter.format(url, APP_ID, rd);
		redirect(url);
	}

	@Clear
	public void logout() {
		AuthUtils.logout(this);
		renderSuccess();
	}

	/**
	 * 用户微信登录
	 */
	@Clear
	public void auth() {
		String code = getPara("code");
		if (StrKit.isBlank(code)) {
			renderError(404);
			return;
		}
		SnsAccessToken snsAccessToken = SnsAccessTokenApi.getSnsAccessToken(APP_ID, APP_SECRET, code);
		String openId = snsAccessToken.getOpenid();
		String accessToken = snsAccessToken.getAccessToken();
		ApiResult snsApi = SnsApi.getUserInfo(accessToken, openId);
		System.out.println(snsApi.getJson());
		/**
		 * 如果用户不存在,创建新用户
		 */
		TpUser user = TpUser.dao.searchFirst("openId", openId);
		if (user == null) {
			user = new TpUser();
			user.setOpenId(openId);
			user.save();
			user.setUid(hashids.encode(user.getId()));
		}
		user.setSex(snsApi.getInt("sex"));
		user.setName(snsApi.getStr("nickname"));
		user.setLogo(snsApi.getStr("headimgurl"));
		user.setCity(snsApi.getStr("city"));
		user.setProvince(snsApi.getStr("province"));
		user.setCountry(snsApi.getStr("country"));
		user.update();
		AuthUtils.login(String.valueOf(user.getId()), this);
		String state = getPara("state");
		if (StrKit.isBlank(state)) {
			redirect("/");
		} else {
			redirect(URLUtil.decode(state));
		}
	}

	/**
	 * 首页,列出活动所有参与者
	 */
	@Override
	public void index() {
		/**
		 * 参与代码
		 */
		Long activityId = getCodeId();
		if (activityId == null) {
			renderFailure(500, "活动代码为空");
			return;
		}
		TpActivity info = TpActivity.dao.findById(activityId);
		if (info == null) {
			renderFailure(500, "活动代码不正确");
			return;
		}
		setAttr("activity", info);
		setAttr("isExpired", info.isExpired() ? 1 : 0);
		SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindActicityJoin", activityId);
		List<Record> items = Db.use("toupiao").find(sqlPara);
		setItems(items);
		render("/toupiao/index.html");
	}

	/**
	 * 参与者详情,如果是参与者特殊处理
	 */
	public void info() {
		Long joinId = getCodeId();
		TpJoin info = TpJoin.dao.findById(joinId);
		if (info.getLogo() != null) {
			String[] logoList = info.getLogo().split(";");
			info.put("logoList", logoList);
		}
		if (info.getImages() != null) {
			String[] imageList = info.getImages().split(";");
			info.put("imageList", imageList);
		}
		TpActivity activity = TpActivity.dao.findById(info.getActivityId());
		setInfoItem(info);
		setAttr("activity", activity);
		setAttr("isExpired", info.isExpired() ? 1 : 0);
		render("/toupiao/info.html");
	}

	public void edit() {
		Long joinId = getCodeId();
		TpJoin info = TpJoin.dao.findById(joinId);
		setInfoItem(info);
		render("/toupiao/edit.html");
	}

	/**
	 * 参加投票活动 过期不允许参加
	 */
	public void join() {
		Long activityId = getCodeId();
		TpActivity info = TpActivity.dao.findById(activityId);
		setAttr("activity", info);
		render("/toupiao/join.html");
	}

	/**
	 * 提交/修改参加投票信息
	 */
	@Override
	public void submit() {
		String activityCode = getPara("activityCode");
		if (activityCode == null) {
			renderFailure(500, "activity code null");
			return;
		}
		Long activityId = hashids.decode(activityCode)[0];
		Long joinId = getJoinId();
		String title = getPara("title");
		String address = getPara("address");
		String coverMediaId = getPara("coverMediaId");
		String logoMediaIds = getPara("logoMediaIds");
		String imageMediaIds = getPara("imageMediaIds");

		TpActivity activity = TpActivity.dao.findById(activityId);
		if (activity.isExpired()) {
			renderFailure(500, "活动已结束");
			return;
		}

		Integer index = activity.getIndex() == null ? 0 : activity.getIndex();

		// 上传封面
		MediaFile coverMediaFile = MediaApi.getMedia(coverMediaId);
		String coverFileName = coverMediaFile.getFileName() + ".jpg";
		File coverFile = new File(PathUtils.getFile("upload", coverFileName));
		BufferedInputStream is = coverMediaFile.getFileStream();
		try {
			inputstreamtofile(is, coverFile);
		} catch (IOException e) {
			e.printStackTrace();
		}
		String coverUrl = UploadUtils.upload(coverFile);

		// 上传宣传图
		System.out.println(logoMediaIds);
		String[] logoIds = logoMediaIds.split(";");
		StringBuffer logoSB = new StringBuffer();
		for (String id : logoIds) {
			if (StrKit.isBlank(id)) {
				continue;
			}
			MediaFile mediaFile = MediaApi.getMedia(id);
			String fileName = mediaFile.getFileName() + ".jpg";
			File file = new File(PathUtils.getFile("upload", fileName));
			BufferedInputStream stream = mediaFile.getFileStream();
			try {
				inputstreamtofile(stream, file);
			} catch (IOException e) {
				e.printStackTrace();
			}
			String url = UploadUtils.upload(file);
			logoSB.append(url).append(";");
		}

		// 上传详情图
		System.out.println(imageMediaIds);
		String[] imageIds = imageMediaIds.split(";");
		StringBuffer imageSB = new StringBuffer();
		for (String id : imageIds) {
			if (StrKit.isBlank(id)) {
				continue;
			}
			MediaFile mediaFile = MediaApi.getMedia(id);
			String fileName = mediaFile.getFileName() + ".jpg";
			File file = new File(PathUtils.getFile("upload", fileName));
			BufferedInputStream stream = mediaFile.getFileStream();
			try {
				inputstreamtofile(stream, file);
			} catch (IOException e) {
				e.printStackTrace();
			}
			String url = UploadUtils.upload(file);
			imageSB.append(url).append(";");
		}

		TpJoin tpJoin;
		if (joinId == null) {
			tpJoin = new TpJoin();
			tpJoin.setActivityId(activityId);
			tpJoin.setUserId(getUser().getId());
			tpJoin.setNo(index + 1);
			tpJoin.setAddTime();
			tpJoin.save();
			tpJoin.setCode(hashids.encode(tpJoin.getId()));
			tpJoin.update();
		} else {
			tpJoin = TpJoin.dao.findById(joinId);
		}
		tpJoin.setTitle(title);
		tpJoin.setAddress(address);
		tpJoin.setLogo(logoSB.toString());
		tpJoin.setImages(imageSB.toString());
		tpJoin.setCover(coverUrl);
		if (tpJoin.update()) {

			SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindActicityJoin", activityId);
			activity.setJoinCount(TpJoin.dao.find(sqlPara).size());
			activity.setIndex(index + 1);
			activity.update();

			renderSuccess();
		} else {
			renderFailure();
		}
	}

	public void inputstreamtofile(InputStream ins, File file) throws IOException {
		OutputStream os = new FileOutputStream(file);
		int bytesRead = 0;
		byte[] buffer = new byte[8192];
		while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
			os.write(buffer, 0, bytesRead);
		}
		os.close();
		ins.close();
	}

	/**
	 * 投票 过期不允许投票
	 */
	public void vote() {
		Long joinId = getCodeId();
		TpJoin info = TpJoin.dao.findById(joinId);
		TpActivity activity = TpActivity.dao.findById(info.getActivityId());
		if (info.isExpired()) {
			renderFailure();
			return;
		}
		TpUser user = getUser();
		if (!canVote(activity, info, user)) {
			renderMsg("每位用户每天只能给一个店铺投" + activity.getVotePerDay() + "票");
			return;
		}
		TpUserVote userVote = new TpUserVote();
		// userVote.setActivityId(activityId);
		userVote.setJoinId(joinId);
		userVote.setUserId(user.getId());
		userVote.save();
		// setAttr("expired", info.isExpired() ? 1 : 0);
		info.setVote(info.getVote() + 1);
		info.update();

		// 更新活动投票统计
		SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindActicityJoin", activity.getId());
		List<TpJoin> list = TpJoin.dao.find(sqlPara);
		int count = 0;
		for (TpJoin join : list) {
			count += join.getVote();
		}
		activity.setVoteCount(count);
		activity.update();
		doRanking(activity.getId());

		renderResult(info.getVote(), "ok", 200);
		// render("/toupiao/voteResult.html");
	}

	private boolean canVote(TpActivity activity, TpJoin join, TpUser user) {
		Cache cache = Redis.use();
		String key = user.getId() + "-" + join.getId();

		String now = DateUtil.now();
		Date nowDate = DateUtil.parse(now);
		long expireTime = DateUtil.between(nowDate, DateUtil.endOfDay(nowDate), DateUnit.SECOND);

		if (cache.exists(key)) {
			int count = cache.get(key);
			if (count < activity.getVotePerDay()) {
				cache.setex(key, new Long(expireTime).intValue(), count + 1);
			} else {
				return false;
			}
		} else {
			cache.setex(key, new Long(expireTime).intValue(), 1);
		}
		return true;
	}

	public void voteResult() {
		Long activityId = getCodeId();
		TpActivity activity = TpActivity.dao.findById(activityId);
		setAttr("activity", activity);
		render("/toupiao/voteResult.html");
	}

	/**
	 * 买钻
	 */
	public void dimond() {
		// Long activityId = getCodeId();
		String code = getPara("code");
		if (code == null) {
			renderFailure(500, "code is null");
			return;
		}
		String joinCode = getPara("joinCode");
		if (joinCode == null) {
			renderFailure(500, "join code is null");
			return;
		}

		Long activityId = hashids.decode(code)[0];
		TpActivity activity = TpActivity.dao.findById(activityId);
		SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindVotePrice", activityId);
		List<TpActivityVote> items = TpActivityVote.dao.find(sqlPara);
		setItems(items);
		setAttr("activity", activity);
		setAttr("joinCode", joinCode);
		render("/toupiao/buyDiamond.html");
	}

	/**
	 * 生成订单
	 * 
	 * @param master
	 * @param userId
	 * @return
	 * @Time 2018年7月19日 下午9:43:06
	 */
	private TpOrder genOrder(TpUser user, TpJoin join, TpActivityVote activityVote) {
		Long userId = user.getId();
		String openId = user.getOpenId();
		TpOrder order = new TpOrder();
		order.setUserId(userId);
		order.setJoinId(join.getId().intValue());
		order.setActivityVoteId(activityVote.getId().intValue());
		order.setPrice(activityVote.getPrice());
		order.setTotalFee(String.valueOf(activityVote.getPrice()));
		order.setOpenId(openId);
		order.save();
		Long orderId = order.getId();
		String no = DateUtil.format(new Date(), "YYYYMMddhhmmss") + orderHash.encode(orderId);
		order.setOrderNo(no);
		order.setOutTradeNo(no);
		order.update();
		return order;
	}

	/**
	 * 支付买钻
	 */
	public void pay() {
		Long id = getParaToLong("id");
		String joinCode = getPara("joinCode");

		TpActivityVote activityVote = TpActivityVote.dao.findById(id);
		if (joinCode == null) {
			renderFailure(500, "code is null");
			return;
		}
		Long joinId = hashids.decode(joinCode)[0];
		TpJoin join = TpJoin.dao.findById(joinId);

		TpOrder order = genOrder(getUser(), join, activityVote);
		if (order == null) {
			renderFailure(500, "generate order failed");
			return;
		}
		String openId = order.getOpenId();
		String outTradeNo = order.getOutTradeNo();
		String total = String.valueOf(Long.valueOf(order.getTotalFee()) * 100L);
		String prepayId = order.getPrePayId();
		Ret ret = payUtils.pushOrder(outTradeNo, total, IpKit.getRealIpV2(getRequest()), openId, prepayId);
		if (ret.isFail()) {
			renderFailure();
			return;
		}
		@SuppressWarnings("unchecked")
		Map<String, String> packageParams = (Map<String, String>) ret.get("packageParams");
		if (StrKit.isBlank(order.getPrePayId())) {
			order.setPrePayId(packageParams.get("package"));
		}
		order.update();
		renderSuccess(packageParams);
	}

	/**
	 * 活动介绍
	 */
	public void intro() {
		Long activityId = getCodeId();
		if (activityId == null) {
			renderFailure(500, "活动代码为空");
			return;
		}
		TpActivity info = TpActivity.dao.findById(activityId);
		if (info == null) {
			renderFailure(500, "活动代码不正确");
			return;
		}
		setAttr("isExpired", info.isExpired() ? 1 : 0);
		setAttr("activity", info);
		render("/toupiao/intro.html");
	}

	/**
	 * 投票结果
	 */
	public void rank() {
		Long activityId = getCodeId();
		if (activityId == null) {
			renderError(404);
			return;
		}
		SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindRank", activityId);
		doRanking(activityId);

		List<TpJoin> list = TpJoin.dao.paginate(getPage(), PAGE_SIZE, sqlPara).getList();
		TpActivity activity = TpActivity.dao.findById(activityId);
		setItems(list);
		setAttr("activity", activity);
		setAttr("isExpired", activity.isExpired() ? 1 : 0);
		setAttr("endTime", activity.getEndTime());
		render("/toupiao/rank.html");
	}

	private void doRanking(Long activityId) {
		SqlPara sqlPara = Db.use("toupiao").getSqlPara("TPFindRank", activityId);
		List<TpJoin> items = TpJoin.dao.paginate(1, 50, sqlPara).getList();
		int lastVote = 0;
		int position = 1;
		for (TpJoin tpJoin : items) {
			tpJoin.setPosition(position);
			int currentVote = tpJoin.getVote();
			if (position == 1) {
				tpJoin.setNextVote(0);
			} else {
				int nextVote = lastVote - currentVote;
				tpJoin.setNextVote(nextVote);
			}
			lastVote = currentVote;
			tpJoin.update();
			position++;
		}
	}

	@Override
	public void add() {
		TpActivity activity = new TpActivity();
		activity.setTitle("测试活动");
		activity.save();
		Long activityId = activity.getId();
		activity.setCode(hashids.encode(activityId));
		activity.update();
		renderSuccess();

		for (int i = 1; i <= 5; i++) {
			TpActivityVote activityVote = new TpActivityVote();
			activityVote.setPrice(i * 5);
			activityVote.setVote(10 * i);
			activityVote.setActivityId(activityId);
			activityVote.save();
		}
		renderSuccess();
	}

}
